-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support separate node announcement addresses #484
Support separate node announcement addresses #484
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this!
Already looks pretty good, one comment though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll also need to account for the new field in may_announce_channel
(and corresponding tests) in this file. We use this method to check whether we allow to open or accept announced channels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked at this but I believe the may_announce_channel
is still correct as-is. announcement_addresses
doesn't change the behavior of when or if a node can announce channels. That is still purely determined by listening_addresses
and alias
. The announcement_addresses
just allows an override for what
addresses are actually announced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you are right! In fact, could you extend the node_announce_channel
test case to assert that may_announce_channel
is still false
if listening_addresses
is None
and announcement_addresses
is Some
?
May also be good to add a check for this and log+abort early in Builder::build_with_store_internal
, so that the user can't ever startup with misconfigured Node
where announcement_addresses
is set but listening_addresses
aren't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both of those suggestions sound good. For the misconfigured node do we want a new error variant or should I re-use the existing BuildError::InvalidAnnouncementAddresses
? I think it's probably fine as long as there's a log_error with explanation alongside it.
Also, I think the check should not only be against unset listening_addresses but actually be if config.announcement_addrresses.is_some() && !may_announce_channel(&config)
.
Basically if you set announcement addresses but the node will not announce then it's misconfigured.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both of those suggestions sound good. For the misconfigured node do we want a new error variant or should I re-use the existing
BuildError::InvalidAnnouncementAddresses
? I think it's probably fine as long as there's a log_error with explanation alongside it.
Yeah, though InvalidListeningAddresses
might make more sense, no?
Basically if you set announcement addresses but the node will not announce then it's misconfigured.
Yeah, that makes sense. FWIW, could do the same for NodeAlias
, as you'd also only expect it to be set if you want to announce your node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well if the check is if config.announcement_addrresses.is_some() && !may_announce_channel(&config)
then we don't know if it's missing listening_addresses or alias and so maybe it makes more sense for the error to be BuildError::InvalidAnnouncementAddresses` in the sense they are invalid because you didn't set the other values? Or we could add a new error specifically for some announcement field set (announcement_addresses or alias) when the node is not going to announce.
Will add the same check for NodeAlias.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, maybe we should switch may_announce_channel
to return a Result<(), AnnounceError>
? Then, we know at the callsites why it can't announce and can take action (mostly log the right thing before returning the corresponding BuildError
) based on the error type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gave this a shot in the latest commit. The error message handling feels a bit verbose now but I tried to dry it up best I could. Check it out and let me know what you think.
@@ -412,6 +417,18 @@ impl NodeBuilder { | |||
Ok(self) | |||
} | |||
|
|||
/// Sets the IP address and TCP port which [`Node`] will announce to the gossip network that it accepts connections on. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we add the 'if unset' note here as well?
src/lib.rs
Outdated
@@ -457,7 +457,9 @@ impl Node { | |||
continue; | |||
} | |||
|
|||
let addresses = if let Some(addresses) = bcast_config.listening_addresses.clone() { | |||
let addresses = if let Some(addresses) = bcast_config.announcement_addresses.clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: use var names such as listening_addresses and announcement_addresses for better readability.
src/lib.rs
Outdated
@@ -457,7 +457,9 @@ impl Node { | |||
continue; | |||
} | |||
|
|||
let addresses = if let Some(addresses) = bcast_config.listening_addresses.clone() { | |||
let addresses = if let Some(addresses) = bcast_config.announcement_addresses.clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably need to update may_announce_channel
and also the code-points where we check for availability of listening addresses for public-channel/announcements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we do. I mentioned this above:
I looked at this but I believe the may_announce_channel is still correct as-is. announcement_addresses doesn't change the behavior of when or if a node can announce channels. That is still purely determined by listening_addresses and alias. The announcement_addresses just allows an override for what addresses are actually announced.
let addresses = if let Some(addresses) = bcast_config.listening_addresses.clone() { | ||
let addresses = if let Some(addresses) = bcast_config.announcement_addresses.clone() { | ||
addresses | ||
} else if let Some(addresses) = bcast_config.listening_addresses.clone() { | ||
addresses | ||
} else { | ||
debug_assert!(false, "We checked whether the node may announce, so listening addresses should always be set"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this log will need to be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it does because listening_addresses is the only thing that should always be set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you are right! In fact, could you extend the node_announce_channel
test case to assert that may_announce_channel
is still false
if listening_addresses
is None
and announcement_addresses
is Some
?
May also be good to add a check for this and log+abort early in Builder::build_with_store_internal
, so that the user can't ever startup with misconfigured Node
where announcement_addresses
is set but listening_addresses
aren't.
src/lib.rs
Outdated
@@ -802,6 +804,11 @@ impl Node { | |||
self.config.listening_addresses.clone() | |||
} | |||
|
|||
/// Returns our own announcement addresses. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this always return the addresses we announce, i.e., fallback to listening_addresses
if announcement_addresses
are None
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I think that probably makes more sense? If they want to see what the actual announcement_addresses
are they can check the node config.
Pushed new commits that address all review feedback. Only consideration left imo is whether or not to introduce new error variant to represent misconfigured announcement parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excuse the delay here.
Only consideration left imo is whether or not to introduce new error variant to represent misconfigured announcement parameters.
Yeah, that could make sense to have a catchall BuildError
that represents any of the failure cases.
The changes mostly look good to me, but we should try to make them a bit less verbose/less redundant. So please just implement Display
for AnnounceError
.
Also, please clean up your git history. Each feature commit should have a short one-line description followed by a body describing what the change does and why it was necessary (see https://cbea.ms/git-commit/ for a rough guideline). I think it would also make sense to squash some of these commits already.
src/builder.rs
Outdated
use crate::{io, NodeMetrics}; | ||
use crate::{may_announce_channel, Node}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Please import may_announce_channel
from config
, not the crate root.
src/builder.rs
Outdated
@@ -412,6 +417,20 @@ impl NodeBuilder { | |||
Ok(self) | |||
} | |||
|
|||
/// Sets the IP address and TCP port which [`Node`] will announce to the gossip network that it accepts connections on. | |||
/// | |||
/// **Note**: If unset, the `listening_addresses` will be used as the list of addresses to announce. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Can we link to listening_addresses? This is not only convenient for users, but also asserts we'll get
cargo doc` failures if the link would ever break going forward.
@@ -766,6 +785,13 @@ impl ArcedNodeBuilder { | |||
self.inner.write().unwrap().set_listening_addresses(listening_addresses).map(|_| ()) | |||
} | |||
|
|||
/// Sets the IP address and TCP port which [`Node`] will announce to the gossip network that it accepts connections on. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please align the docs on the uniffi
variant with the non-uniffi
variant.
src/builder.rs
Outdated
let error_msg_for = |prefix: &str| -> String { | ||
match err { | ||
AnnounceError::MissingNodeAlias => | ||
format!("{} set but the node will not announce itself as node alias is not configured. Please set a node alias.", prefix), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we always need to specify what is set, but only the failure condition. To this end, please just implement Display
for AnnounceError
rather than introducing this custom closure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm okay, might need help with the error message because to me the failure condition is that some but not all of the fields required to enable node announcement were set.
We don't really know if their intention was to have the node be announced or not and so just telling them to set node alias or that node alias wasn't configured makes it sound like it's required but it's really only required if they intend to have their node announced.
Not sure if I'm making sense but I will go ahead with implementing Display
for AnnounceError
and we can finalize the actual messages later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm okay, might need help with the error message because to me the failure condition is that some but not all of the fields required to enable node announcement were set.
We don't really know if their intention was to have the node be announced or not and so just telling them to set node alias or that node alias wasn't configured makes it sound like it's required but it's really only required if they intend to have their node announced.
Ah, I see your point. Well we can still implement Display
for AnnounceError
, while adding (some, concise) context while logging.
Not sure if I'm making sense but I will go ahead with implementing
Display
forAnnounceError
and we can finalize the actual messages later.
SGTM
36b6ca4
to
c98a403
Compare
Ok I incorporated the feedback and added a Display implementation for AnnounceError which simplified some of the error logging. I also went back and cleaned up my commit history. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, thanks for addressing the feedback so far!
It would be great if we could add a new test case that simply sets up two nodes, opens an announced channel, and checks that the counterparty will indeed see the correct announcement_addresses
and node_alias
set in their network graph once it's updated. You should be able to basically copy the setup part from simple_bolt12_send_receive
test, as there we already open an announced channel and wait until it propagates. Mind taking a stab at that in a separate/third commit?
src/config.rs
Outdated
@@ -117,6 +117,10 @@ pub struct Config { | |||
/// **Note**: We will only allow opening and accepting public channels if the `node_alias` and the | |||
/// `listening_addresses` are set. | |||
pub listening_addresses: Option<Vec<SocketAddress>>, | |||
/// The addresses which the node will announce to the gossip network that it accepts connections on. | |||
/// | |||
/// **Note**: If unset, the `listening_addresses` will be used as the list of addresses to announce. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Also link listening_addresses
here.
src/builder.rs
Outdated
if let Err(err) = may_announce_channel(&config) { | ||
if config.announcement_addresses.is_some() { | ||
log_error!(logger, "Announcement addresses were set but some required configuration options for node announcement are missing: {}", err); | ||
return Err(match err { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Let's use a variable for the returned error and use the matches!
macro.
src/config.rs
Outdated
pub(crate) enum AnnounceError { | ||
MissingNodeAlias, | ||
MissingListeningAddresses, | ||
MissingBoth, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rename this MissingAliasAndAddresses
.
c98a403
to
68d5bad
Compare
Have fixed the nits you mentioned above and pushed a new commit that adds a new integration test that configures one node with both listening and announcement addresses and the other node with just listening addresses and asserts that they both receive the expected addresses. |
src/builder.rs
Outdated
/// | ||
/// **Note**: If unset, the [`listening_addresses`] will be used as the list of addresses to announce. | ||
/// | ||
/// [`listening_addresses`]: NodeBuilder::set_listening_addresses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use Self::set_listening_addresses
here as NodeBuilder
is private under the uniffi
feature, hence this breaking doc builds.
tests/integration_tests_rust.rs
Outdated
|
||
// Assert that the aliases and addresses match the expected values | ||
assert_eq!( | ||
node_a_info.announcement_info.as_ref().unwrap().alias(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is failing CI as under the uniffi
feature the API behaves slightly differntly:
error[E0599]: no method named `alias` found for reference `&ldk_node::graph::NodeAnnouncementInfo` in the current scope
--> tests/integration_tests_rust.rs:950:51
|
950 | node_a_info.announcement_info.as_ref().unwrap().alias(),
| ^^^^^-- help: remove the arguments
| |
| field, not a method
error[E0599]: no method named `addresses` found for reference `&ldk_node::graph::NodeAnnouncementInfo` in the current scope
--> tests/integration_tests_rust.rs:954:51
|
954 | node_a_info.announcement_info.as_ref().unwrap().addresses(),
| ^^^^^^^^^-- help: remove the arguments
| |
| field, not a method
error[E0599]: no method named `alias` found for reference `&ldk_node::graph::NodeAnnouncementInfo` in the current scope
--> tests/integration_tests_rust.rs:959:51
|
959 | node_b_info.announcement_info.as_ref().unwrap().alias(),
| ^^^^^-- help: remove the arguments
| |
| field, not a method
error[E0599]: no method named `addresses` found for reference `&ldk_node::graph::NodeAnnouncementInfo` in the current scope
--> tests/integration_tests_rust.rs:963:51
|
963 | node_b_info.announcement_info.as_ref().unwrap().addresses(),
| ^^^^^^^^^-- help: remove the arguments
| |
| field, not a method
We probably need a feature gate here that makes the checks use one or the other API depending on whether uniffi
is set or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, just saw these uniffi issues. Will set up separate feature-gated asserts to handle it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, fixed the test and looks like CI is passing.
In certain node configurations a user might want or need to announce different addresses to the network than the ones they bind their tcp listeners to.
This error type can provide more context to callers about why the node configuration does not support channel announcements.
68d5bad
to
eea1fa9
Compare
A new integration test that configures nodes using the new announcement addresses configuration. Ensures that both nodes receive the correct alias and address for nodes using and not using this new feature.
eea1fa9
to
5432ed8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much! LGTM!
Fixes #422
Users running ldk-node in a container and/or behind a NAT will often want to or be forced to bind to a different address than they announce to the network.
This PR introduces a new
announcement_addresses
configuration option that operates the same waylistening_addresses
does but is used for constructing the node announcement message. An emptyannouncement_addresses
will operate exactly the same way as today by defaulting tolistening_addresses
.